﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;

namespace Cdp
{
    public delegate void AsyncUdpEventHandler(object sender, CdpDatagram data);
    public delegate void CdpEventHandler(object sender, CdpDatagram data);

    public class CdpDatagram
    {
        public CdpDatagram() { }
        public CdpDatagram(EndPoint address, byte[] data, int offset, int bytesTransferred)
        {
            RemoteEndPoint = address;
            Buffer = data;
            Offset = offset;
            BytesTransferred = bytesTransferred;            
        }
        public EndPoint RemoteEndPoint { get; set; }
        public byte[] Buffer { get; set; }
        public int Offset { get; set; }
        public int BytesTransferred { get; set; }
        public int RTT { get; set; }
    }

    public class CdpEndPoint
    {
        public EndPoint RemoteEndPoint;
        public bool IsConnected;
        public short MTU;
        public int RTT;
        public CdpGenerater Generater;
    }

    public class AsyncUserToken
    {
        public EndPoint RemoteEndPoint { get; set; }
    }

    public class SocketAsyncEventArgsPool
    {
        Queue<SocketAsyncEventArgs> pool;

        public SocketAsyncEventArgsPool(int capacity)
        {
            pool = new Queue<SocketAsyncEventArgs>(capacity);
        }

        public void Push(SocketAsyncEventArgs arg)
        {
            if (arg != null)
                lock (pool)
                {
                    pool.Enqueue(arg);
                }
        }

        public SocketAsyncEventArgs Pop()
        {
            lock (pool)
            {
                return pool.Dequeue();
            }
        }

        public bool IsEmpty()
        {
            lock (pool)
            {
                if (pool.Count == 0)
                    return true;
                else
                    return false;
            }
        }
    }

    public class BufferManager
    {
        int m_numBytes;                 
        byte[] m_buffer;                
        Stack<int> m_freeIndexPool;     
        int m_currentIndex;
        int m_bufferSize;

        public BufferManager(int totalBytes, int bufferSize)
        {
            m_numBytes = totalBytes;
            m_currentIndex = 0;
            m_bufferSize = bufferSize;
            m_freeIndexPool = new Stack<int>();
        }

        public void InitBuffer()
        {
            m_buffer = new byte[m_numBytes];
        }

        public bool SetBuffer(SocketAsyncEventArgs args)
        {

            if (m_freeIndexPool.Count > 0)
            {
                args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize);
            }
            else
            {
                if ((m_numBytes - m_bufferSize) < m_currentIndex)
                {
                    return false;
                }
                args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize);
                m_currentIndex += m_bufferSize;
            }
            return true;
        }

        public void FreeBuffer(SocketAsyncEventArgs args)
        {
            m_freeIndexPool.Push(args.Offset);
            args.SetBuffer(null, 0, 0);
        }
    }    
        
}
